using System;
using System.Collections;

namespace Pegasus.Collections
{
	/// <summary>
	/// Summary description for UniqueSortedList.
	/// </summary>
	public class UniqueSortedList : IEnumerable
	{
		private static object placeHolder = new object();
		private SortedList list;

		#region Constructors
		/// <summary>
		/// Initializes a new instance of the UniqueSortedList class that is empty,
		/// has the default initial capacity and is sorted according to the IComparable 
		/// interface implemented by each key added to the UniqueSortedList
		/// </summary>
		public UniqueSortedList()
		{
			this.list = new SortedList();
		}
		
		/// <summary>
		/// Initializes a new instance of the <see cref="UniqueSortedList">UniqueSortedList</see> class that is empty,
		/// has the specified initial capacity and is sorted according to the IComparable interface implemented by each key added to the SortedList.
		/// </summary>
		/// <param name="capacity"></param>
		public UniqueSortedList( int capacity ) 
		{
			this.list = new SortedList( capacity );
		}
		
		/// <summary>
		/// Initializes a new instance of the <see cref="UniqueSortedList">UniqueSortedList</see> class that is empty,
		/// has the default initial capacity and is sorted according to the IComparable interface passed in.
		/// </summary>
		public UniqueSortedList( IComparer comparer )
		{
			this.list = new SortedList( comparer );
		}
		
		/// <summary>
		/// Initializes a new instance of the <see cref="UniqueSortedList">UniqueSortedList</see> class that contains elements copied from the specified dictionary,
		/// has the same initial capacity as the number of elements copied and is sorted according to the IComparable interface implemented by each key.
		/// </summary>
		public UniqueSortedList( IDictionary d )
		{
			this.list = new SortedList( d.Count );
			foreach ( DictionaryEntry entry in d )
			{
				Add( entry.Value );
			}
		}
		
		/// <summary>
		/// Initializes a new instance of the <see cref="UniqueSortedList">UniqueSortedList</see> class that is empty,
		/// has the specified initial capacity and is sorted according to the IComparable interface passed in.
		/// </summary>
		public UniqueSortedList( IComparer comparer, int capacity ) 
		{
			this.list = new SortedList( comparer,  capacity );
		}
		
		/// <summary>
		/// Initializes a new instance of the <see cref="UniqueSortedList">UniqueSortedList</see> class that contains elements copied from the specified dictionary,
		/// has the same initial capacity as the number of elements copied and is sorted according to the specified IComparer interface.
		/// </summary>
		/// <param name="d"></param>
		/// <param name="comparer"></param>
		public UniqueSortedList( IDictionary d, IComparer comparer ) 
		{
			this.list = new SortedList( comparer );
			foreach ( DictionaryEntry entry in d )
			{
				Add( entry.Value );
			}
		}
		#endregion
		
		#region Public Properties
		/// <summary>
		/// Gets the number of items in the UniqueSortedList
		/// </summary>
		public int Count
		{
			get { return this.list.Count; }
		}

		/// <summary>
		/// Gets all of the items in this as an
		/// object[].
		/// </summary>
		public object[] AllItems
		{
			get
			{
				object[] items = new object[ this.list.Count ];
				int index = 0;

				foreach ( DictionaryEntry entry in this.list )
				{
					items[ index ] = entry.Key;
					++index;
				}
				return items;
			}
		}
		
		/// <summary>
		/// Gets the value located at the specified index in the <see cref="UniqueSortedList">UniqueSortedList</see>.
		/// </summary>
		public object this[ int index ]
		{
			get
			{
				object key = null;
				if ( index < this.list.Count )
				{
					key = this.list.GetKey( index );
				}
				else
				{
					throw new IndexOutOfRangeException( "Index must be less than the size of the UniqueSortedList and non-negative" );
				}
				return key;
			}
		}
		#endregion
	
		#region Public Methods
		/// <summary>
		/// Adds the object only if the object isn't contained already
		/// </summary>
		/// <param name="o"></param>
		public void Add( object o )
		{
			// we don't care about the values
			// we only care that we keep the keys unique
			if ( ! this.list.ContainsKey( o ) )
			{
				this.list.Add( o, placeHolder );
			}
		}
		
		/// <summary>
		/// Indicates whether or not the specified object is contained
		/// in the <see cref="UniqueSortedList">UniqueSortedList</see>
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		public bool Contains( object key )
		{
			return this.list.ContainsKey( key );
		}

		/// <summary>
		/// Returns an IDictionaryEnumerator that can iterate through the UniqueSortedList.
		/// </summary>
		/// <returns><see cref="IDictionaryEnumerator">IDictionaryEnumerator</see></returns>
		public IEnumerator GetEnumerator()
		{
			return new UniqueSortedListEnumerator( this );	
		}
		#endregion

		#region UniqueSortedListEnumerator
		/// <summary>
		/// Implements an enumerator for the UniqueSortedList
		/// </summary>
		private class UniqueSortedListEnumerator : IEnumerator
		{
			UniqueSortedList sortedList;
			object current;
			int internalIndex;

			public UniqueSortedListEnumerator( UniqueSortedList list )
			{
				this.sortedList = list;	
				Reset();
			}
			#region IEnumerator Members

			/// <summary>
			/// Resets the enumerator to point to the first item
			/// in the list.
			/// </summary>
			public void Reset()
			{
				if ( this.sortedList != null && this.sortedList.list.Count > 0 )
				{
					this.current = this.sortedList[ 0 ];
					this.internalIndex = 0;
				}
			}

			/// <summary>
			/// Gets the current object in the list
			/// </summary>
			public object Current
			{
				get { return this.current; }
			}

			/// <summary>
			/// Moves the current object in the list to the next
			/// if there are more objects in the list.
			/// </summary>
			/// <returns>false if there are no more objects in the list, true otherwise</returns>
			public bool MoveNext()
			{
				if ( this.internalIndex >= this.sortedList.Count )
				{
					return false;
				}
				this.current = this.sortedList[ this.internalIndex ];
				++this.internalIndex;

				return true;
			}

			#endregion
		}
		#endregion
	}
}
